package ru.positron;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

public class GetFeedServlet extends HttpServlet {
	private static final long serialVersionUID = 1472501608635093314L;

	static Logger LOG = Logger.getLogger(OsmRssSpatialFilter.class.getName());

	/*
	 * public static String getFeedUrl(String source) { String urlbase =
	 * "http://positron96.appspot.com/osmfilter.rss?feed="; try { return
	 * urlbase+URLEncoder.encode(source, "UTF-8"); } catch
	 * (UnsupportedEncodingException e) { return urlbase+source; } }
	 */

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		String sSourceUrl = req.getParameter("url");
		if (sSourceUrl == null) {
			replyError(resp, "No URL provided!");
			return;
		}
		if (!sSourceUrl.startsWith("http://"))	sSourceUrl = "http://" + sSourceUrl;

		URL sourceUrl;
		try {
			sourceUrl = new URL(sSourceUrl);
		} catch (MalformedURLException e) {
			replyError(resp, "URL " + sSourceUrl + " is bad");
			return;
		}

		if (sSourceUrl.matches("/http:\\/\\/(www.)?openstreetmap\\.org\\/browse\\/changesets\\/feed.*/i")) {
			replyLink(resp, sSourceUrl);
			return;
		}

		String type = null;
		InputStream is = null;
		try {
			Utils.ResponseResult dlResult = Utils.downloadAndHeader(sourceUrl, "Content-Type");
			is = dlResult.content;
			type = dlResult.header;
		} catch(IOException e) {
			replyError(resp, "Could not fetch requested URL");
			LOG.log(Level.WARNING, "IOException while fetching: ", e);
			return;
		} catch(Exception e) {
			if (e.getCause() instanceof java.net.SocketTimeoutException) {
				replyError(resp, "There was a timeout fetching feed. Please try again");
				LOG.info("Timeout for " + sSourceUrl);
				return;
			}
			replyError(resp, "Could not fetch requested URL");
			LOG.log(Level.WARNING, "Exception while fetching: ", e);
			return;
		}

		if ( (type==null) || (type != null && type.startsWith("text/html")) ) {
			byte[] bb = readStream(is);
			Document doc = Jsoup.parse(new String(bb));
			Element link = doc
					.select("head > link[rel=alternate][href~=.+][type~=(application/(rss|(x(\\.|\\-))?atom|rdf)\\+|text/)xml]")
					.first();
			if (link == null) {
				replyError(resp, "This page does not contain RSS or ATOM feeds");
				return;
			}
			replyLink(resp, link.absUrl("href"));
			return;
		} else 
		if (type != null && (
				type.startsWith("application/atom+xml") || 
				type.startsWith("application/rss+xml") ||
				type.startsWith("text/xml") )) {
			replyLink(resp, sSourceUrl);
			return;
		} else {
			replyError(resp, "This page has bad content-type: " + type);
			LOG.info("Bad content-type=" + type + " for url " + sSourceUrl);
			return;
		}

	}

	private byte[] readStream(InputStream is) throws IOException {
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		int rd;
		byte[] b = new byte[2048];
		while ((rd = is.read(b)) != -1) {
			os.write(b, 0, rd);
		}
		return os.toByteArray();
	}

	private void replyError(HttpServletResponse resp, String err) {
		LOG.warning("Replying error: "+err);
		reply(resp, "{\"result\":0, \"message\":\"" + err + "\"}");
		// reply(resp, "\""+err+"\"" );
	}

	private void replyLink(HttpServletResponse resp, String link) {
		/*
		 * reply(resp, "<div class=\"urldata\">This is a link to filtered feed:"
		 * + "<a href=\""+link+"\">"+link+"</a>" +
		 * "You can copy and paste it into your favorite RSS-aggregator</div>");
		 */
		reply(resp, String.format("{\"result\":1,\"url\":\"%s\"}", link));
	}

	private void reply(HttpServletResponse resp, String string) {
		try {
			resp.setContentType("application/json");
			PrintWriter wr = resp.getWriter();
			wr.println(string);
		} catch (IOException e) {
			LOG.warning("Error while sending output: " + e);
		}

	}

}
